/*
 * \brief  Core-specific instance of the IRQ session interface
 * \author Christian Helmuth
 * \date   2007-09-13
 */

/*
 * Copyright (C) 2007-2009 Christian Helmuth
 * Genode Labs, Feske & Helmuth Systementwicklung GbR
 *
 * This file is part of the Genode OS framework, which is distributed
 * under the terms of the GNU General Public License version 2.
 */

#ifndef _CORE__INCLUDE__IRQ_SESSION_COMPONENT_H_
#define _CORE__INCLUDE__IRQ_SESSION_COMPONENT_H_

#include <base/lock.h>
#include <util/list.h>

#include <irq_session/server.h>
#include <irq_session/capability.h>

/* XXX Notes
 *
 * - each H/W IRQ is an irq thread
 * - each irq thread has an Server_entrypoint
 * -> irq thread is special Server_activation
 * -> IRQ session is Server_object
 *
 * - session("IRQ", "irq_num=<num>") -> Capability(irq_thread, cap)
 *   - cap must be generated at CAP
 *   - cap must be managed by irq_thread-local Server_entrypoint
 *
 * - irq thread states
 *   1. wait_for_client --[ client calls wait_for_irq     ]--> 2.
 *   2. wait_for_irq    --[ kernel signals irq            ]--> 3.
 *   3. irq_occured     --[ inform client about occurence ]--> 1.
 *
 * - irq thread roles
 *   - Irq_server (Ipc_server) for client
 *   - Fiasco_irq_client (Ipc_client) at kernel
 */

namespace Genode {

	class Irq_session_component : public Irq_session_server,
	                              public List<Irq_session_component>::Element
	{
		private:

			class Irq_control_client
			{
				private:

					Msgbuf<32> _snd_buf, _rcv_buf;
					Ipc_client _ipc_client;

				public:

					Irq_control_client(Capability control)
					: _ipc_client(control, &_snd_buf, &_rcv_buf) { }

					bool associate_to_irq(unsigned irq_number)
					{
						bool ok = false;
						_ipc_client << 0  /* fake function ID */
						            << irq_number << IPC_CALL
						            >> ok;
						return ok;
					}
			};

			class Irq_control_server : public Server_object
			{
				private:

					/**
					 * Associate to IRQ at Fiasco
					 *
					 * This is executed by the IRQ server activation itself.
					 */
					bool _associate_to_irq(unsigned irq_number);

				public:

					int dispatch(int op, Ipc_istream &is, Ipc_ostream &os)
					{
						unsigned irq_number = 0;
						is >> irq_number;
						os << _associate_to_irq(irq_number);
						return 0;
					}
			};

			unsigned                 _irq_number;
			Range_allocator         *_irq_alloc;

			Msgbuf<32>               _snd_msg, _rcv_msg;
			Server_activation<2048>  _activation;
			Server_entrypoint        _ep;

			/*
			 * On Pistachio, an IRQ is unmasked right after attaching.
			 * Hence, the kernel may send an IRQ IPC when the IRQ hander is
			 * not explicitly waiting for an IRQ but when it is waiting for
			 * a client's 'wait_for_irq' RPC call. To avoid this conflict, we
			 * lazily associate to the IRQ when calling the 'wait_for_irq'
			 * function for the first time. We use the '_irq_attached' flag
			 * for detecting the first call. On other kernels, this variable
			 * may be unused.
			 */
			unsigned _irq_attached;  /* true if IRQ is already attached */


			/********************************************
			 ** IRQ control server (internal use only) **
			 ********************************************/

			Irq_control_server       _control_server;  /* ctrl server */
			Capability               _control_cap;     /* capability for ctrl server */
			Irq_control_client       _control_client;  /* ctrl client */
			Irq_session_capability   _irq_cap;         /* capability for IRQ */

		public:

			/**
			 * Constructor
			 *
			 * \param cap_session  capability session to use
			 * \param irq_alloc    platform-dependent IRQ allocator
			 * \param args         session construction arguments
			 */
			Irq_session_component(Cap_session     *cap_session,
			                      Range_allocator *irq_alloc,
			                      const char      *args);

			/**
			 * Destructor
			 */
			~Irq_session_component();

			/**
			 * Return capability to this session
			 *
			 * If an initialization error occurs, returned _cap is invalid.
			 */
			Irq_session_capability cap() const { return _irq_cap; }


			/***************************
			 ** Irq session interface **
			 ***************************/

			void wait_for_irq();
	};
}

#endif /* _CORE__INCLUDE__IRQ_SESSION_COMPONENT_H_ */
